package org.dant.ant.extension.net.processors;

import java.io.*;
import java.util.*;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.dant.ant.extension.net.DefaultDispatcher;
import org.dant.ant.extension.net.repository.ProcessGroup;
import org.dant.ant.extension.net.repository.ProcessItem;
import org.dant.ant.extension.tasks.internal.RemoteResponse;
import org.dant.ant.extension.utils.StringUtils;
import org.dant.apache.tools.ant.taskdefs.ExecTask;

public abstract class StartApp extends ExecTask implements Runnable {
    protected String[] args;
    protected String[] envs;

    protected List duplicateProcesses = new ArrayList();

    protected List resultsList = new ArrayList();
  
    protected boolean blocking;
    protected boolean unique;
    protected int duplicate = 1;
    protected List expectlist = new LinkedList();
  
    protected long start;
    protected long end;

    protected ProcessGroup processGroup;

    public abstract String getProcessKey();

    public void setProcessGroup(ProcessGroup group) {
        this.processGroup = group;
    }

    public ProcessGroup getProcessGroup() {
        return this.processGroup;
    }
  
    public void setExpectedList(List e) {
        this.expectlist = e;
    }

    public void setDuplicate(int d) {
        this.duplicate = d;
    }

    public int getDuplicate() {
        return this.duplicate;
    }

    public void setBlocking(boolean b) {
        this.blocking = b;
    }

    public boolean getBlocking() {
        return this.blocking;
    }

    public void setUnique(boolean u) {
        this.unique = u;
    }

    public boolean getUnique() {
        return this.unique;
    }
  
    public void setArguments(String[] a) {
        this.args = a;
        cmdl.addArguments(args);
    }

    public void setEnvironment(String[] e) {
        this.envs = e;
    }
  
    public void checkProcess() {
        if(getUnique()) {
            DefaultDispatcher.getProcessRepository().checkProcess(getProcessKey());
        }
    }
  
    public void addProcess(Process process, String processID) {
        DefaultDispatcher.getProcessRepository().getProcessDestroyer().add(process);
        addProcess(getProcessKey(), process, processID);
    }

    public void addProcess(String key, Process process, String processID) {
        System.out.println("Push a process <" + StringUtils.hideLongString(key) + "> into the process map");

        ProcessItem pi = new ProcessItem();
        pi.setStartTime(System.currentTimeMillis());
        pi.setTimeOut(timeout.longValue());
        pi.setProcessID(processID);
        pi.add(process);

        pi.setStatus("Running");
    
        processGroup.add(pi);
    }

    public void setup() {
        if (timeout == null || timeout.longValue() <= 0) {
            // set timeout to 2 hours
            setTimeout(new Long(1000 * 60 * 60 * 2));  
        }
        // Setup a fake project
        this.setProject(new Project());
    }

    private void aggregateResponse(RemoteResponse response) {
        for (Iterator iter = resultsList.iterator(); iter.hasNext();) {
            RemoteResponse results = (RemoteResponse) iter.next();
            if (!results.isSuccess()) {
                response.setSuccess(false);
            }
            if (!"N/A".equals(results.getResult())) {
                response.appendResult(results.getResult());
            }
            response.appendStdErrBuffer(results.getStdErrBuffer().toString());
            response.appendStdOutBuffer(results.getStdOutBuffer().toString());
            response.setCommandType(results.getCommandType());
        }
        response.setDuplicate(this.duplicate);
        response.setCommand(getProcessKey());
        response.setStartTime(start);
        response.setEndTime(end);

    }

    public void start(RemoteResponse response) {
        setup();
        this.start = System.currentTimeMillis();
        execute();
        this.end = System.currentTimeMillis();
        aggregateResponse(response);
    }

    public void run() {
        super.execute();
    }

    public void execute() throws BuildException {
        System.out.println("Dant daemon is going to start  " + duplicate + " processes... ");
        for (int i = 0; i < duplicate; i++) {
            Thread execThread = new Thread(this);
            duplicateProcesses.add(execThread);
            execThread.start();
        }
    
        for (Iterator iter = duplicateProcesses.iterator(); iter.hasNext();) {
            try {
                ((Thread)iter.next()).join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
